import collections
import datetime
import logging

import google.protobuf.json_format as json_format
from absl import app, flags

import pandas as pd

import coin.research.read_strat_info as rsi
from coin.proto.coin_strategy_pb2 import StrategyLog
from coin.support.proto_log.logic.util import run_from_strat_log_archive


def flatten(dictionary, parent_key=False, separator='.'):
  """
  Turn a nested dictionary into a flattened dictionary
  :param dictionary: The dictionary to flatten
  :param parent_key: The string to prepend to dictionary's keys
  :param separator: The string used to separate flattened keys
  :return: A flattened dictionary
  """

  items = []
  for key, value in dictionary.items():
    new_key = str(parent_key) + separator + key if parent_key else key
    if isinstance(value, getattr(collections, 'abc', collections).MutableMapping):
      items.extend(flatten(value, new_key, separator).items())
    elif isinstance(value, list):
      for k, v in enumerate(value):
        items.extend(flatten({str(k): v}, new_key).items())
    else:
      items.append((new_key, value))
  return dict(items)


class OnLog(object):
  def __init__(self, symbol):
    self.record_list = []
    self.symbol = symbol

  def on_log(self, timestamp, log):
    pb = StrategyLog()
    pb.ParseFromString(log)
    data = json_format.MessageToDict(pb, preserving_proto_field_name=True)
    if self.symbol in str(data):
      data['timestamp'] = timestamp
      self.record_list.append(flatten(data))


def dump_og(strategy_name, start_time, end_time, symbol, machine):
  """
  Dump all og logs in a dataframe
  :param symbol: symbol filter
  :return a dataframe
  """
  if not isinstance(start_time, datetime.datetime):
    if len(start_time) == 19 and start_time.is_digit():
      start_time = int(start_time)
    if len(end_time) == 19 and end_time.is_digit():
      end_time = int(end_time)
    start_time = pd.to_datetime(start_time).to_pydatetime()
    end_time = pd.to_datetime(end_time).to_pydatetime()
  strategy_infos = rsi.get_strategy_info(trading_date=start_time.date(),
                                         strategy_name=strategy_name)
  strategy_info = [s for s in strategy_infos if symbol is None or symbol in s['subsymbol']][0]
  # market_type = strategy_info['market_type']
  # exchange = strategy_info['exchange']
  if symbol is None:
    symbol = strategy_info.get('symbol', '')
  if machine is None:
    machine = strategy_info['machine']
  onlog = OnLog(symbol)
  run_from_strat_log_archive(on_log_callback=onlog.on_log,
                             start_time=start_time,
                             end_time=end_time,
                             root_dir='/remote/iosg/strat-1/buckets/log.raw.coin/live/strat_proto_log',
                             machine=machine,
                             strategy_name=strategy_name)
  return pd.DataFrame(onlog.record_list)


# ./pyrunner python/coin/support/proto_log/app/og_log_dumper.py --strategy_name delta_mgr_prex --start_time=20210812-112000  --end_time 20210812-114000  --csv_path=tmp.csv --symbol=MATIC
def main(_):
  f = flags.FLAGS
  df = dump_og(f.strategy_name, f.start_time, f.end_time, f.symbol, f.machine)
  df.to_csv(f.csv_path)


if __name__ == '__main__':
  flags.DEFINE_string('strategy_name', '', '')
  flags.DEFINE_string('start_time', '20200802', '')
  flags.DEFINE_string('end_time', '20200802-235959', '')
  flags.DEFINE_string('csv_path', 'tmp.csv', '')
  flags.DEFINE_string('symbol', None, '')
  flags.DEFINE_string('machine', None, 'set if you know the machine')

  logging.basicConfig(level='DEBUG', format='%(levelname)8s %(asctime)s %(name)s] %(message)s')
  app.run(main)
